/**
 * 能处理字符串组成公式的计算器
 * 
 * 1、支持多括号的符合运算
 * 2、支持无效括号的自动忽略，不会报错
 * 3、未实现出错提示的校验，暂时只能处理正确公式
 * 4、实现方案为判断符号优先级，看到括号，把括号中的内容递归
 * 5、这个方案性能不够完美，日后会实现一个无需递归的方案。
 */
package test;

import java.util.Stack;

/**
 * @author leiruiqi
 *
 */
public class Calucate {

	
	public static Double recursiveCalStr(String str) throws Exception{
		//符号操作符堆栈
		Stack<Character> op = new Stack<Character>();		
		//数字操作符堆栈
		Stack<Double> number = new Stack<Double>();
		//符号标记，如果出现一个符号，如+ - * / ( ) 会纪录mark = i+1,这样就能使用str.subString(mark,i) 来获取数字（大多时候是两个符号之间的字符串）
		int mark=0;
		//左括号的再字符串中的index，仅仅是出现的第一个左括号
		int LeftBracketsIndex = 0;
		//左括号的个数，用于计算对应的右括号的，0表示没有左括号
		int j=0;
		Double temp = null;
		for (int i = 0; i < str.length(); i++) {
			char c = str.charAt(i);
			//如果是符号 || 左括号个数大于0(j>0) 
			if (j > 0 || isSignBrackets(c)) {
				//左括号就 j++
				if (c == '(') {
					j++;
					//如果是一个左括号，纪录下标LeftBracketsIndex
					if (j == 1) {
						LeftBracketsIndex = i;
					}
				}
				//右括号就 j--
				if (c == ')') {
					j--;
					//如果找到第一个左括号对应的右括号(j==0)
					if (j == 0) {
						//递归计算括号内的str对应的数值
						temp = recursiveCalStr(str.substring(LeftBracketsIndex + 1, i));
						
						mark = i + 1;
					}
				}
				continue;
			}

			if (isSignCalu(c)) {
				Double d;
				//temp不为空表示有括号内计算的临时数值为待计算数值，通常右括号结束后跟着一个操作符
				if (temp != null) {
					d = temp;
					temp = null;
				} else {//没有temp ，则用str.substring(mark, i) 获取待计算数值
					String tempNumberStr = str.substring(mark, i);
					d = Double.parseDouble(tempNumberStr);
				}
				//堆栈为空，无需比较，直接把操作符和操作数压入堆栈
				if (op.isEmpty()) {
					op.push(c);
					number.push(d);
				} else {
					//否者需要比较堆栈中的操作符，看当前操作符和堆栈中的操作符，哪个优先级更高
					if (compareLevel(c, op.peek())) {
						//优先级高，则把当前操作符和操作数压入堆栈，待循环比较下一个操作数的优先级
						op.push(c);
						number.push(d);
					} else {
						//优先级低，则让堆栈中的操作数和操作符出堆栈，和当前的操作数计算
						d = cal(op.pop(), number.pop(), d);
						//计算完毕，把计算结果和当前的操作符压入堆栈，待循环比较下一个操作数的优先级
						op.push(c);
						number.push(d);
					}

				}
				mark = i + 1;
			}

		}
		//循环结束后如果temp不为空表示以括号结束，不需要再截取字符串找操作数，直接用temp参与计算
		Double d;
		if (temp != null) {
			d = temp;
			temp = null;
		} else {
			String tempNumberStr = str.substring(mark);
			d = Double.parseDouble(tempNumberStr);
		}
		
		//堆栈不为空，循环做出栈运算
		while(!op.isEmpty()){
			d = cal(op.pop(), number.pop(), d);
		}
		return d;
	}
	
	public static int findRightBracketsIndex(String str) throws Exception{
		int j = 0;
		for(int i=0;i<str.length();i++){
			char c = str.charAt(i);
			if(c=='('){
				j++;
				continue;
			}
			if(c=='('){
				j--;
				if(j==0){
					return i;
				}
			}
		}
		throw new Exception("xxxx");
	}
	public static Double cal(char c,double a,double b) throws Exception{
		switch(c){
		case '+':
			return a+b;
		case '-':
			return a-b;
		case '*':
			return a*b;
		case '/':
			return a/b;
		default:
			throw new Exception("XX");	
		}
	}
	
	public static boolean compareLevel(char a,char b){
		if(a=='*'||a=='/'){
			if(b=='+'||b=='-'){
				return true;
			}
		}
		return false;
	}
	public static boolean isSign(char c){
		if(!isSignCalu(c)){
			return isSignBrackets(c);
		}else{
			return true;
		}
	}
	public static boolean isSignCalu(char c){
		if(c=='+'||c=='-'||c=='*'||c=='/'){
			return true;
		}
		return false;
	}
	
	public static boolean isNumber(char c){
		if(c=='0'||c=='1'||c=='2'||c=='3'||c=='4'||c=='5'||c=='6'||c=='7'||c=='8'||c=='9'){
			return true;
		}
		return false;
	}
	public static boolean isSignBrackets(char c){
		if(c=='('||c==')'){
			return true;
		}
		return false;
	}
	
	public static void main(String[] args) {
		try {
			Double a = Calucate.recursiveCalStr("0.6+((((3-1)/(2+1))))+3");
			System.out.println(a);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}